using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace CustomPlate
{
	public class Plate : Control
	{
		public static readonly DependencyProperty ItemTemplateProperty;

		public static readonly RoutedEvent OnSelectionChangedRoutedEvent;

		public static readonly DependencyProperty MultiSelectProperty;

		private Grid _Grid;

		private List<ColumnHeader> _ColumnHeaderList = new List<ColumnHeader>();

		private List<RowHeader> _RowHeaderList = new List<RowHeader>();

		private List<Cell> _CellList = new List<Cell>();

		private IList _ItemSource;

		private int _ColumnCount;

		private int _RowCount;

		private bool _MouseDown;

		private Rectangle _selectingRect = new Rectangle();

		public Style ItemTemplate
		{
			get
			{
				return (Style)GetValue(ItemTemplateProperty);
			}
			set
			{
				SetValue(ItemTemplateProperty, value);
			}
		}

		public bool MultiSelect
		{
			get
			{
				return (bool)GetValue(MultiSelectProperty);
			}
			set
			{
				SetValue(MultiSelectProperty, value);
			}
		}

		public event RoutedEventHandler OnSelectionChanged
		{
			add
			{
				AddHandler(OnSelectionChangedRoutedEvent, value);
			}
			remove
			{
				RemoveHandler(OnSelectionChangedRoutedEvent, value);
			}
		}

		static Plate()
		{
			ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(Style), typeof(Plate), new PropertyMetadata(null));
			OnSelectionChangedRoutedEvent = EventManager.RegisterRoutedEvent("OnSelectionChangedRoutedEvent", RoutingStrategy.Bubble, typeof(EventHandler<RoutedEventArgs>), typeof(Plate));
			MultiSelectProperty = DependencyProperty.Register("MultiSelect", typeof(bool), typeof(Plate), new PropertyMetadata(true));
			FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(Plate), new FrameworkPropertyMetadata(typeof(Plate)));
		}

		public void RaiseSelectedChanaged()
		{
			RaiseEvent(new RoutedEventArgs
			{
				RoutedEvent = OnSelectionChangedRoutedEvent
			});
		}

		public Plate()
		{
			base.TargetUpdated += Plate_TargetUpdated;
		}

		protected override void OnPreviewKeyDown(KeyEventArgs e)
		{
			if (e.Key == Key.Down || e.Key == Key.Return || e.Key == Key.Up || e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Tab)
			{
				List<Cell> list = _CellList.Where((Cell s) => s.IsSelected).ToList();
				if (list.Count > 0)
				{
					int num = _CellList.IndexOf(list[0]);
					int num2 = num / _ColumnCount;
					int num3 = num % _ColumnCount;
					do
					{
						if (e.Key == Key.Down || e.Key == Key.Return)
						{
							if (num2 == _RowCount - 1 && num3 == _ColumnCount - 1)
							{
								num2 = 0;
								num3 = 0;
							}
							else if (num2 == _RowCount - 1)
							{
								num2 = 0;
								num3++;
							}
							else
							{
								num2++;
							}
						}
						else if (e.Key == Key.Up)
						{
							if (num2 == 0 && num3 == 0)
							{
								num3 = _ColumnCount - 1;
								num2 = _RowCount - 1;
							}
							else if (num2 == 0)
							{
								num2 = _RowCount - 1;
								num3--;
							}
							else
							{
								num2--;
							}
						}
						else if (e.Key == Key.Left || (e.Key == Key.Tab && (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift))
						{
							if (num2 == 0 && num3 == 0)
							{
								num3 = _ColumnCount - 1;
								num2 = _RowCount - 1;
							}
							else if (num3 == 0)
							{
								num3 = _ColumnCount - 1;
								num2--;
							}
							else
							{
								num3--;
							}
						}
						else if (e.Key == Key.Right || e.Key == Key.Tab)
						{
							if (num2 == _RowCount - 1 && num3 == _ColumnCount - 1)
							{
								num2 = 0;
								num3 = 0;
							}
							else if (num3 == _ColumnCount - 1)
							{
								num3 = 0;
								num2++;
							}
							else
							{
								num3++;
							}
						}
					}
					while (!_CellList[num2 * _ColumnCount + num3].IsEnabled);
					foreach (Cell item in list)
					{
						item.IsSelected = false;
					}
					_CellList[num2 * _ColumnCount + num3].IsSelected = true;
				}
				else
				{
					_CellList[0].IsSelected = true;
				}
				RefreshRowColumnHeaderStatus();
				RaiseSelectedChanaged();
				e.Handled = true;
			}
			base.OnPreviewKeyDown(e);
		}

		private void Plate_TargetUpdated(object sender, DataTransferEventArgs e)
		{
			if (!(e.OriginalSource is Cell) || !(e.Property.Name == "IsSelected"))
			{
				return;
			}
			List<int> list = new List<int>();
			List<int> list2 = new List<int>();
			for (int i = 0; i < _CellList.Count; i++)
			{
				int item = i / _ColumnCount;
				int item2 = i % _ColumnCount;
				Cell cell = _CellList[i];
				if (cell.IsSelected)
				{
					if (!list.Contains(item))
					{
						list.Add(item);
					}
					if (!list2.Contains(item2))
					{
						list2.Add(item2);
					}
				}
			}
			for (int j = 0; j < _RowHeaderList.Count; j++)
			{
				_RowHeaderList[j].IsSelected = list.Contains(j);
			}
			for (int k = 0; k < _ColumnHeaderList.Count; k++)
			{
				_ColumnHeaderList[k].IsSelected = list2.Contains(k);
			}
		}

		public void SetItems(IList itemSource, int row = 8, int column = 12)
		{
			_ColumnCount = column;
			_RowCount = row;
			_ItemSource = itemSource;
			Reload();
		}

		public void SelectAll()
		{
			foreach (Cell cell in _CellList)
			{
				cell.IsSelected = true;
			}
			foreach (ColumnHeader columnHeader in _ColumnHeaderList)
			{
				columnHeader.IsSelected = true;
			}
			foreach (RowHeader rowHeader in _RowHeaderList)
			{
				rowHeader.IsSelected = true;
			}
			RaiseSelectedChanaged();
		}

		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
			_Grid = GetTemplateChild("PART_Grid") as Grid;
			if (_Grid == null)
			{
				_Grid = new Grid();
			}
			Reload();
		}

		public void Reload()
		{
			if (_Grid == null || _ColumnCount == 0 || _RowCount == 0 || _ItemSource == null || _ItemSource.Count < _ColumnCount * _RowCount)
			{
				return;
			}
			_ColumnHeaderList.Clear();
			_RowHeaderList.Clear();
			_CellList.Clear();
			_Grid.Children.Clear();
			_Grid.ColumnDefinitions.Clear();
			_Grid.RowDefinitions.Clear();
			Button button = new Button();
			button.SetResourceReference(FrameworkElement.StyleProperty, "Plate_SelectAllButtonStyle");
			button.Click += BtnSelectAll_Click;
			_Grid.Children.Add(button);
			_Grid.ColumnDefinitions.Add(new ColumnDefinition
			{
				Width = new GridLength(20.0, GridUnitType.Pixel)
			});
			_Grid.RowDefinitions.Add(new RowDefinition
			{
				Height = new GridLength(20.0, GridUnitType.Pixel)
			});
			for (int i = 0; i < _ColumnCount; i++)
			{
				_Grid.ColumnDefinitions.Add(new ColumnDefinition());
				ColumnHeader columnHeader = new ColumnHeader();
				columnHeader.Text = (i + 1).ToString();
				Grid.SetColumn(columnHeader, i + 1);
				Grid.SetRow(columnHeader, 0);
				_Grid.Children.Add(columnHeader);
				_ColumnHeaderList.Add(columnHeader);
			}
			for (int j = 0; j < _RowCount; j++)
			{
				_Grid.RowDefinitions.Add(new RowDefinition());
				RowHeader rowHeader = new RowHeader();
				rowHeader.Text = ((char)(j + 65)).ToString();
				Grid.SetColumn(rowHeader, 0);
				Grid.SetRow(rowHeader, j + 1);
				_Grid.Children.Add(rowHeader);
				_RowHeaderList.Add(rowHeader);
			}
			for (int k = 0; k < _RowCount; k++)
			{
				for (int l = 0; l < _ColumnCount; l++)
				{
					Cell cell = new Cell();
					Grid.SetColumn(cell, l + 1);
					Grid.SetRow(cell, k + 1);
					cell.Style = ItemTemplate;
					cell.DataContext = _ItemSource[k * _ColumnCount + l];
					_Grid.Children.Add(cell);
					_CellList.Add(cell);
				}
			}
		}

		private void BtnSelectAll_Click(object sender, RoutedEventArgs e)
		{
			SelectAll();
		}

		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
		{
			Focus();
			CaptureMouse();
			_MouseDown = true;
			_selectingRect.LeftTop = Mouse.GetPosition(this);
			_selectingRect.RightBottom = _selectingRect.LeftTop;
			RefreshSelectStatus(false);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			if (_MouseDown && MultiSelect)
			{
				_selectingRect.RightBottom = Mouse.GetPosition(this);
				RefreshSelectStatus(true);
				e.Handled = true;
				base.OnMouseMove(e);
			}
		}

		protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
		{
			_MouseDown = false;
			ReleaseMouseCapture();
			RaiseSelectedChanaged();
			base.OnMouseLeftButtonUp(e);
		}

		private void RefreshSelectStatus(bool mouseMove)
		{
			if (_Grid == null || (_selectingRect.Left <= _Grid.ColumnDefinitions[0].ActualWidth && _selectingRect.Top <= _Grid.RowDefinitions[0].ActualHeight))
			{
				return;
			}
			List<Cell> list = new List<Cell>();
			List<Cell> list2 = new List<Cell>();
			if (MultiSelect && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
			{
				list2 = _CellList.Where((Cell s) => s.IsSelected).ToList();
			}
			if (_selectingRect.Left < _Grid.ColumnDefinitions[0].ActualWidth && _selectingRect.Top > _Grid.RowDefinitions[0].ActualHeight)
			{
				for (int i = 0; i < _RowHeaderList.Count; i++)
				{
					int num = i;
					int num2 = 0;
					RowHeader rowHeader = _RowHeaderList[i];
					double num3 = (double)num2 * rowHeader.ActualWidth;
					double num4 = (double)num * rowHeader.ActualHeight + _Grid.RowDefinitions[0].ActualHeight;
					double right = num3 + rowHeader.ActualWidth;
					double bottom = num4 + rowHeader.ActualHeight;
					if (_selectingRect.IntersectsWith(new Rectangle(num3, num4, right, bottom)))
					{
						for (int j = 0; j < _ColumnCount; j++)
						{
							list.Add(_CellList[i * _ColumnCount + j]);
						}
					}
				}
			}
			else if (_selectingRect.Left > _Grid.ColumnDefinitions[0].ActualWidth && _selectingRect.Top < _Grid.RowDefinitions[0].ActualHeight)
			{
				for (int k = 0; k < _ColumnHeaderList.Count; k++)
				{
					int num5 = 0;
					int num6 = k;
					ColumnHeader columnHeader = _ColumnHeaderList[k];
					double num7 = (double)num6 * columnHeader.ActualWidth + _Grid.ColumnDefinitions[0].ActualWidth;
					double num8 = (double)num5 * columnHeader.ActualHeight;
					double right2 = num7 + columnHeader.ActualWidth;
					double bottom2 = num8 + columnHeader.ActualHeight;
					if (_selectingRect.IntersectsWith(new Rectangle(num7, num8, right2, bottom2)))
					{
						for (int l = 0; l < _RowCount; l++)
						{
							list.Add(_CellList[l * _ColumnCount + k]);
						}
					}
				}
			}
			else
			{
				for (int m = 0; m < _CellList.Count; m++)
				{
					int num9 = m / _ColumnCount;
					int num10 = m % _ColumnCount;
					Cell cell = _CellList[m];
					double num11 = (double)num10 * cell.ActualWidth + _Grid.ColumnDefinitions[0].ActualWidth;
					double num12 = (double)num9 * cell.ActualHeight + _Grid.RowDefinitions[0].ActualHeight;
					double right3 = num11 + cell.ActualWidth;
					double bottom3 = num12 + cell.ActualHeight;
					if (_selectingRect.IntersectsWith(new Rectangle(num11, num12, right3, bottom3)))
					{
						list.Add(cell);
					}
				}
			}
			for (int n = 0; n < _CellList.Count; n++)
			{
				Cell cell2 = _CellList[n];
				if (mouseMove)
				{
					cell2.IsSelected = list.Contains(cell2) || list2.Contains(cell2);
				}
				else
				{
					cell2.IsSelected = list.Contains(cell2) ^ list2.Contains(cell2);
				}
			}
			RefreshRowColumnHeaderStatus();
		}

		private void RefreshRowColumnHeaderStatus()
		{
			List<int> list = new List<int>();
			List<int> list2 = new List<int>();
			for (int i = 0; i < _CellList.Count; i++)
			{
				int item = i / _ColumnCount;
				int item2 = i % _ColumnCount;
				Cell cell = _CellList[i];
				if (cell.IsSelected)
				{
					if (!list.Contains(item))
					{
						list.Add(item);
					}
					if (!list2.Contains(item2))
					{
						list2.Add(item2);
					}
				}
			}
			for (int j = 0; j < _RowHeaderList.Count; j++)
			{
				_RowHeaderList[j].IsSelected = list.Contains(j);
			}
			for (int k = 0; k < _ColumnHeaderList.Count; k++)
			{
				_ColumnHeaderList[k].IsSelected = list2.Contains(k);
			}
		}
	}
}
